package rj.cometome;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import java.sql.Struct;

import android.opengl.GLES20;
import android.opengl.Matrix;
import android.util.Log;

@SuppressWarnings("unused")
public class Arrow {
    final String m_strVShader = 
    		"uniform mat4 u_MVPMatrix;" +
    		"uniform mat4 u_MVMatrix;" + 
    		"uniform vec3 u_LightPos;" +
    		
			"attribute vec4 a_position;" +
			"attribute vec3 a_normal;" +
			
    		"attribute vec2 a_texCoords;" +
    		"varying vec2 v_texCoords;" +
    		
    		"void main()" +
    		"{" +
    		"v_texCoords = a_texCoords;" +
    		"gl_Position = u_MVPMatrix * a_position;" +
    		"}";
    
    final String m_strFShader = "precision mediump float;" +
    		"uniform sampler2D u_texID;" +
    		"varying vec2 v_texCoords;" +
    		"void main()" +
    		"{" +
    		"gl_FragColor = texture2D(u_texID, v_texCoords);" +
    		"}";
    
    //The arrow has 14 vertices. Descriptions are viewing the arrow from the back
    final Point3d[] m_pUniqueVerts = {
    		//tail
    		new Point3d( 1, 1,-2), //0 top right rear 
    		new Point3d(-1, 1,-2), //1 top left rear
    		new Point3d(-1,-1,-2), //2 bottom left rear
    		new Point3d( 1,-1,-2), //3 bottom right rear
    		new Point3d( 1, 1, 0), //4 top right front
    		new Point3d(-1, 1, 0), //5 top left front
    		new Point3d(-1,-1, 0), //6 bottom left front
    		new Point3d( 1,-1, 0), //7 bottom right front
    		//head
    		new Point3d( 2, 1, 0), //8 top right base
    		new Point3d(-2, 1, 0), //9 top left base
    		new Point3d(-2,-1, 0), //10 bottom left base
    		new Point3d( 2,-1, 0), //11 bottom right base  
    		//new Point3d( 0, 1, 2), //12 top tip  
    		//new Point3d( 0,-1, 2), //13 bottom tip
    		new Point3d( 0, 0, 2),
    		new Point3d( 0, 0, 2)
    		 
    };
    
    final float[] m_fVertices = new float[126]; 
    
    final short[] m_iIndices = {
    		//Taper
    		0,1,2, 0,2,3,
    		4,5,6, 4,6,7,
    		8,9,10, 8,10,11,
    		12,13,14, 12,14,15,
    		16,17,18, 16,18,19,
    		//Pyramid
    		20,21,22, 20,22,23,
    		24,25,26, 24,26,27,
    		28,29,30, 28,30,31,
    		32,33,34, 32,34,35,
    		36,37,38,
    		39,40,41,
    };
    
    final float[] m_fTexCoords = {
    		//Taper
    		1,0.7f, 1,1, 0.7f,1, 0.7f,0.7f,
    		1,0.7f, 1,1, 0.7f,1, 0.7f,0.7f,
    		1,0.7f, 1,1, 0.7f,1, 0.7f,0.7f,
    		1,1,1,1,1,1,
    		1,1,1,1,1,1,
    		//Pyramid
    		1,0.7f, 1,1, 0.7f,1, 0.7f,0.7f,
    		1,0.7f, 1,1, 0.7f,1, 0.7f,0.7f,
    		1,0.7f, 1,1, 0.7f,1, 0.7f,0.7f,
    		1,0.7f, 1,1, 0.7f,1, 0.7f,0.7f,
    		0,0,0,0,0,0,
    		0,0,0,0,0,0,
    };
    
    float[] m_fCenter = new float[3];
    
    LocationsHandler m_locHandler;
    float m_fRotationSpeed = 0.033f;
	int m_iProgram;
	int m_iPosition;
	int m_iColor;
	int m_iMVPMatrix;
	int m_iTexID;
	int m_iTexLoc;
	int m_iTexCoords;
	Thread m_tLogic;
	ArrowLoop m_Loop;
	float m_fEulerX = 0;
	float m_fEulerY = 0;
	float m_fEulerZ = 0;    
    Quaternion3d m_qTarget;
    Quaternion3d m_qCurrent;
    Vector3d m_vOrientation;  
    FloatBuffer m_vertBuffer = null;
    FloatBuffer m_texCoordBuffer = null;
    ShortBuffer m_indexBuffer = null;
    float[] m_fRotationM = new float[16];
    float[] m_fScaleM = new float[16];
    
    public Arrow() {
    	m_fCenter = calcCenter();
    	copyVerts();
    	
    	m_vertBuffer = ByteBuffer.allocateDirect(m_fVertices.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
    	m_vertBuffer.put(m_fVertices).position(0);
    	
    	m_texCoordBuffer = ByteBuffer.allocateDirect(m_fTexCoords.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
    	m_texCoordBuffer.put(m_fTexCoords).position(0);
    	
    	m_indexBuffer = ByteBuffer.allocateDirect(m_iIndices.length * 4).order(ByteOrder.nativeOrder()).asShortBuffer();
    	m_indexBuffer.put(m_iIndices).position(0);  
    	
    	Matrix.setIdentityM(m_fScaleM, 0);
    	
    	m_vOrientation = new Vector3d(0,0,0);
    	m_vOrientation.x = m_pUniqueVerts[m_pUniqueVerts.length - 1].x - m_fCenter[0];
    	m_vOrientation.y = m_pUniqueVerts[m_pUniqueVerts.length - 1].y - m_fCenter[1];
    	m_vOrientation.z = m_pUniqueVerts[m_pUniqueVerts.length - 1].z - m_fCenter[2];
    	
    	m_qCurrent = Quaternion3d.identity();
    	m_qTarget = Quaternion3d.identity();
    	m_Loop = new ArrowLoop(this);
    	m_locHandler = LocationsHandler.getInstance();
    }
    
    public void load(CtMView view) {
    	m_iProgram = Utils.LoadProgram(m_strVShader, m_strFShader);
    	m_iPosition = GLES20.glGetAttribLocation(m_iProgram, "a_position");
    	m_iMVPMatrix = GLES20.glGetUniformLocation(m_iProgram, "u_MVPMatrix");
    	m_iTexLoc = GLES20.glGetUniformLocation(m_iProgram, "u_texID");
    	m_iTexCoords = GLES20.glGetAttribLocation(m_iProgram, "a_texCoords");
    	m_iTexID = Utils.LoadTexture(view, R.drawable.arrowtex);
    	
    	m_tLogic = new Thread() {
    		@Override
    		public void run() {
    			m_Loop.startLoop();
    		}
    	};
    	
    	m_tLogic.start();
    }
    
    int counter = 0;
    float xRot = 0;
    float yRot = 0;
    float zRot = 0;
    
    public void update() {
    	float[] locrots = m_locHandler.getRotation();
    	//Log.d("ROTS", locrots[0] + " " + locrots[1] + " " + locrots[2]);
    	float x = locrots[0] - Utils.toRadians(m_locHandler.getBearing());
    	float y = locrots[1];
    	float z = 0.0f - locrots[2];
    	setRotateEuler(locrots[0], locrots[1], locrots[2]);
    	//setRotateEuler(Utils.toRadians(locrots[0]), Utils.toRadians(locrots[1]), Utils.toRadians(locrots[2]));  		
    }
    
    public void draw(float[] mvpMatrix) {
    	m_qCurrent = Quaternion3d.slerp(m_qCurrent, m_qTarget, m_fRotationSpeed);
    	m_vOrientation = Quaternion3d.rotateVector(m_qCurrent, m_vOrientation);
    	Matrix.setIdentityM(m_fRotationM, 0);
    	Matrix.translateM(m_fRotationM, 0, m_fCenter[0], m_fCenter[1], m_fCenter[2]);
    	Quaternion3d.setMatrixFromQuaternion(m_fRotationM, m_qCurrent);
    	
    	GLES20.glUseProgram(m_iProgram);
    	
    	GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
    	GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, m_iTexID);
    	GLES20.glUniform1i(m_iTexLoc, 0);
    	
    	m_vertBuffer.position(0);
    	GLES20.glVertexAttribPointer(m_iPosition, 3, GLES20.GL_FLOAT, false, 0, m_vertBuffer);
    	GLES20.glEnableVertexAttribArray(m_iPosition);
    	
    	m_texCoordBuffer.position(0);
    	GLES20.glVertexAttribPointer(m_iTexCoords, 2, GLES20.GL_FLOAT, false, 0, m_texCoordBuffer);
    	GLES20.glEnableVertexAttribArray(m_iTexCoords);
    	
    	float[] result = new float[16];
    	
    	Matrix.multiplyMM(result, 0, mvpMatrix, 0, m_fRotationM, 0);
    	//Matrix.multiplyMM(result,0,mvpMatrix,0,m_locHandler.rotationMatrix,0);
    	Matrix.multiplyMM(mvpMatrix, 0, result, 0, m_fScaleM, 0);
    	
    	GLES20.glUniformMatrix4fv(m_iMVPMatrix, 1, false, mvpMatrix, 0);
    	GLES20.glDrawElements(GLES20.GL_TRIANGLES, m_iIndices.length, GLES20.GL_UNSIGNED_SHORT, m_indexBuffer);
    }
    
    public void scaleUniform(float factor) {
    	Matrix.scaleM(m_fScaleM, 0, factor, factor, factor);
    }
    
    public void rotateToPoint(float x, float y, float z) {
    	Vector3d targetV = new Vector3d(x,y,z);
    	Vector3d axis = Vector3d.crossProduct(targetV, m_vOrientation);
    	float angle = (float)Math.acos(Vector3d.dotProduct(targetV, m_vOrientation));
    	
    	m_qTarget = Quaternion3d.fromAxisAndAngle(axis, angle);
    }
    
    public void rotateEuler(float xAngle, float yAngle, float zAngle) {
    	m_fEulerX += xAngle;
    	m_fEulerY += yAngle;
    	m_fEulerZ += zAngle;
    	m_qTarget = Quaternion3d.fromEulerAngles(m_fEulerX, m_fEulerY, m_fEulerZ);
    }
    
    public void setRotateEuler(float xAngle, float yAngle, float zAngle) {
    	m_fEulerX = xAngle;
    	m_fEulerY = yAngle;
    	m_fEulerZ = zAngle;
    	m_qTarget = Quaternion3d.fromEulerAngles(m_fEulerX, m_fEulerY, m_fEulerZ);
    }
    
    public float[] calcCenter() {
    	float[] rtnVal = new float[3];
    	
    	for (int i = 0; i < m_pUniqueVerts.length; ++i) {
    		rtnVal[0] += m_pUniqueVerts[i].x;
    		rtnVal[1] += m_pUniqueVerts[i].y;
    		rtnVal[2] += m_pUniqueVerts[i].z;
    	}
    	
    	rtnVal[0] /= (float)m_pUniqueVerts.length;
    	rtnVal[1] /= (float)m_pUniqueVerts.length;
    	rtnVal[2] /= (float)m_pUniqueVerts.length;
    	
    	return rtnVal;
    }
    
    private void copyVerts() {
    	//Taper
    	//front
    	System.arraycopy(m_pUniqueVerts[0].getArray(), 0, m_fVertices, 0, 3);
    	System.arraycopy(m_pUniqueVerts[1].getArray(), 0, m_fVertices, 3, 3);
    	System.arraycopy(m_pUniqueVerts[2].getArray(), 0, m_fVertices, 6, 3);
    	System.arraycopy(m_pUniqueVerts[3].getArray(), 0, m_fVertices, 9, 3);
    	//left
    	System.arraycopy(m_pUniqueVerts[1].getArray(), 0, m_fVertices, 12, 3);
    	System.arraycopy(m_pUniqueVerts[5].getArray(), 0, m_fVertices, 15, 3);
    	System.arraycopy(m_pUniqueVerts[6].getArray(), 0, m_fVertices, 18, 3);
    	System.arraycopy(m_pUniqueVerts[2].getArray(), 0, m_fVertices, 21, 3);
    	//right
    	System.arraycopy(m_pUniqueVerts[4].getArray(), 0, m_fVertices, 24, 3);
    	System.arraycopy(m_pUniqueVerts[0].getArray(), 0, m_fVertices, 27, 3);
    	System.arraycopy(m_pUniqueVerts[3].getArray(), 0, m_fVertices, 30, 3);
    	System.arraycopy(m_pUniqueVerts[7].getArray(), 0, m_fVertices, 33, 3);
    	//top
    	System.arraycopy(m_pUniqueVerts[4].getArray(), 0, m_fVertices, 36, 3);
    	System.arraycopy(m_pUniqueVerts[5].getArray(), 0, m_fVertices, 39, 3);
    	System.arraycopy(m_pUniqueVerts[1].getArray(), 0, m_fVertices, 42, 3);
    	System.arraycopy(m_pUniqueVerts[0].getArray(), 0, m_fVertices, 45, 3);
    	//bottom
    	System.arraycopy(m_pUniqueVerts[3].getArray(), 0, m_fVertices, 48, 3);
    	System.arraycopy(m_pUniqueVerts[2].getArray(), 0, m_fVertices, 51, 3);
    	System.arraycopy(m_pUniqueVerts[6].getArray(), 0, m_fVertices, 54, 3);
    	System.arraycopy(m_pUniqueVerts[7].getArray(), 0, m_fVertices, 57, 3);
    	
    	//Pyramid
    	//right out
    	System.arraycopy(m_pUniqueVerts[8].getArray(), 0, m_fVertices, 60, 3);
    	System.arraycopy(m_pUniqueVerts[4].getArray(), 0, m_fVertices, 63, 3);
    	System.arraycopy(m_pUniqueVerts[7].getArray(), 0, m_fVertices, 66, 3);
    	System.arraycopy(m_pUniqueVerts[11].getArray(), 0, m_fVertices, 69, 3);
    	//right up
    	System.arraycopy(m_pUniqueVerts[12].getArray(), 0, m_fVertices, 72, 3);
    	System.arraycopy(m_pUniqueVerts[8].getArray(), 0, m_fVertices, 75, 3);
    	System.arraycopy(m_pUniqueVerts[11].getArray(), 0, m_fVertices, 78, 3);
    	System.arraycopy(m_pUniqueVerts[13].getArray(), 0, m_fVertices, 81, 3);
    	//left up
    	System.arraycopy(m_pUniqueVerts[9].getArray(), 0, m_fVertices, 84, 3);
    	System.arraycopy(m_pUniqueVerts[12].getArray(), 0, m_fVertices, 87, 3);
    	System.arraycopy(m_pUniqueVerts[13].getArray(), 0, m_fVertices, 90, 3);
    	System.arraycopy(m_pUniqueVerts[10].getArray(), 0, m_fVertices, 93, 3);
    	//left out
    	System.arraycopy(m_pUniqueVerts[5].getArray(), 0, m_fVertices, 96, 3);
    	System.arraycopy(m_pUniqueVerts[9].getArray(), 0, m_fVertices, 99, 3);
    	System.arraycopy(m_pUniqueVerts[10].getArray(), 0, m_fVertices, 102, 3);
    	System.arraycopy(m_pUniqueVerts[6].getArray(), 0, m_fVertices, 105, 3);
    	//top
    	System.arraycopy(m_pUniqueVerts[12].getArray(), 0, m_fVertices, 108, 3);
    	System.arraycopy(m_pUniqueVerts[9].getArray(), 0, m_fVertices, 111, 3);
    	System.arraycopy(m_pUniqueVerts[8].getArray(), 0, m_fVertices, 114, 3);
    	//bottom
    	System.arraycopy(m_pUniqueVerts[13].getArray(), 0, m_fVertices, 117, 3);
    	System.arraycopy(m_pUniqueVerts[11].getArray(), 0, m_fVertices, 120, 3);
    	System.arraycopy(m_pUniqueVerts[10].getArray(), 0, m_fVertices, 123, 3);
    }
}